﻿using System;
using System.Data;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Web.Mvc;
using System.Xml.Linq;
using Dqaqs.Data;
using Dqaqs.Services.ServiceContracts;
using Dqaqs.Web.Common;

namespace Dqaqs.Web.Controllers
{
	public class ProjectController : Controller
	{
		//
		// GET: /Project/

		protected override void OnException(ExceptionContext filterContext)
		{
			if (filterContext.HttpContext.IsCustomErrorEnabled)
			{
				filterContext.ExceptionHandled = true;
			}
			base.OnException(filterContext);
			//OVERRIDE THE 500 ERROR  
			filterContext.HttpContext.Response.StatusCode = 200;

			var ex = filterContext.Exception;
			ViewBag.ErrorMsg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
		}

		public ActionResult Index()
		{
			return RedirectToAction("List");
		}

		public ActionResult List()
		{
			TempData["SelectedMenu"] = "Projects";
			TempData["SelectedSubMenu"] = "Select Project";

			var svc = GetProjectService();
			var projs = svc.ListProjects();

			return View(projs);
		}

		public ActionResult Select(Guid id)
		{
			SelectProject(GetProject(id));
			return RedirectToAction("List");
		}

		public ActionResult New()
		{
			TempData["SelectedMenu"] = "Projects";
			TempData["SelectedSubMenu"] = "New Project";

			return View();
		}
		
		[HttpPost]
		[HandleError(View="../Common/CustomError")]
		public ActionResult New(Project project )
		{
			TempData["SelectedMenu"] = "Projects";
			TempData["SelectedSubMenu"] = "New Project";
			try
			{
				//New project
				var svc = GetProjectService();
				svc.NewProject(project);
				SelectProject(project);
				return RedirectToAction("List");
			}
			catch (Exception ex)
			{
				return HandleException(ex);
			}
		}

		private ActionResult HandleException(Exception ex)
		{
			ViewBag.ErrorMsg = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
			return View("../Common/CustomError");
		}

		public ActionResult Edit(Guid? id)
		{
			TempData["SelectedMenu"] = "Projects";
			TempData["SelectedSubMenu"] = "Edit Project";

			if (id == null && Session["_Project"] == null)
			{
				return RedirectToAction("CustomError", "Common", new {errorMsg = "No project selected"});
			}

			id = id ?? ((Project) Session["_Project"]).Id;
			var prj = GetProject(id.Value);
			SelectProject(prj);
			return View(prj);
		}

		[HttpPost]
		public ActionResult Edit(Project project)
		{
			TempData["SelectedMenu"] = "Projects";
			TempData["SelectedSubMenu"] = "Edit Project";

			try
			{
				var svc = GetProjectService();
				var validatedSchema = svc.ProcessSchema(project.Schema);
				project.Schema = validatedSchema;
				svc.UpdateProject(project);
				return View(project);
			}
			catch (Exception ex)
			{
				return HandleException(ex);
			}
		}

		public ActionResult Detail(Guid? id)
		{
			TempData["SelectedMenu"] = "Projects";
			TempData["SelectedSubMenu"] = "Project Details";

			if (id == null && Session["_Project"] == null)
			{
				return RedirectToAction("CustomError", "Common", new {errorMsg = "No project selected"});
			}

			id = id ?? ((Project) Session["_Project"]).Id;
			var prj = GetProject(id.Value);
			SelectProject(prj);
			return View(prj);
		}

		public ActionResult Delete(Guid id)
		{
			var svc = GetProjectService();
			svc.DeleteProject(id);
			if (Session["_Project"] != null && id == ((Project)Session["_Project"]).Id)
				Session["_Project"] = null;
			return RedirectToAction("List");
		}

		public ActionResult Schema(Guid? id, bool json=false)
		{
			var rv = InitializeAction(id, "Global Schema", null);
			if (rv != null) return rv;

			id = id ?? ((Project)Session["_Project"]).Id;
			var svc = GetProjectService();
			try
			{
				var prj = svc.GetProject(id.Value);
				if (json)
				{
					return Json(Data.Schema.Parse(prj.Schema), JsonRequestBehavior.AllowGet);
				}
				var unprocessedSchema = SchemaXmlToText(prj.Schema);
				prj.Schema = unprocessedSchema;
				return View(prj);
			}
			catch(Exception ex)
			{
				return HandleException(ex);
			}
		}

		private static string SchemaXmlToText(string schema)
		{
			if (string.IsNullOrEmpty(schema))
				return string.Empty;
			var el = XElement.Parse(schema);
			var tables = el.Elements("Table").Select(l => new
			{
				table = l.Attribute("Name").Safe(a => a.Value),
				columns =
			l.Elements("Column").
			Select(cl => new { name = cl.Attribute("Name").Safe(a => a.Value),
				iskey = cl.Attribute("IsKey").Safe(a => a.Value),
				type = (string)cl.Attribute("Type")}).ToList()
			}).ToList();

			var sb = new StringBuilder();
			foreach (var table in tables)
			{
				sb.AppendLine();
				sb.Append("+ ");
				sb.AppendLine(table.table);
				foreach (var col in table.columns)
				{
					sb.Append("-- ");
					if ("true".Equals(col.iskey))
						sb.Append("*");
					sb.AppendFormat("{0} ( {1} )", col.name, col.type);
					sb.AppendLine();
				}
			}
			return sb.ToString();
		}

		[HttpPost]
		public ActionResult Schema(Project project)
		{
			var svc = GetProjectService();
			try
			{
				var prj = svc.GetProject(project.Id);
				var validatedSchema = svc.ProcessSchema(project.Schema);
				prj.Schema = validatedSchema;
				svc.UpdateProject(prj);
				return View(prj);
			}
			catch(Exception ex)
			{
				return HandleException(ex);
			}
		}

		public ActionResult ValidateSchema(string schema)
		{
			try
			{
				var svc = GetProjectService();
				var rv = svc.ValidateSchema(Server.HtmlDecode(schema));
				if (string.IsNullOrEmpty(rv))
					return Json(new {Success = true}, JsonRequestBehavior.AllowGet);
				return Json(new {Error = rv}, JsonRequestBehavior.AllowGet);
			}
			catch(SyntaxErrorException ex)
			{
				return Json(new { Error = ex.Message }, JsonRequestBehavior.AllowGet);
			}
		}

		public ActionResult GetSchema(Guid projectId)
		{
			try
			{
				var svc = GetProjectService();
				var prj = svc.GetProject(projectId);
				return Json(JsonHelper.PrepareSchemaForJson(prj.Schema), JsonRequestBehavior.AllowGet);
			}
			catch (Exception)
			{
				
				throw;
			}
		}

		private ActionResult InitializeAction(Guid? id, string menu, string subMenu)
		{
			TempData["SelectedMenu"] = menu;
			TempData["SelectedSubMenu"] = subMenu;

			if (id == null && Session["_Project"] == null)
			{
				return RedirectToAction("CustomError", "Common", new { errorMsg = "No project selected" });
			}
			return null;
		}

		private void SelectProject(Project project)
		{
			Session["_project"] = project;
		}

		private static Project GetProject(Guid id)
		{
			var svc = GetProjectService();
			return svc.GetProject(id);
		}

		private static IProjectService GetProjectService()
		{
			var binding = new BasicHttpBinding();
			var address = new EndpointAddress(
											"http://localhost:8732/Design_Time_Addresses/Dqaqs/ProjectService/");
			var fact = new ChannelFactory<IProjectService>(binding, address);
			var ch = fact.CreateChannel();
			return ch;
		}
	}
}
